import datetime
import socket
import requests
import urllib3
import ping3
from fastapi import HTTPException


urllib3.disable_warnings()


class HeartBeat:

    @classmethod
    def _heartbeat(cls, *args, **kwargs):
        pass
    
    @classmethod
    def heartbeat(cls, *args, **kwargs):
        """心跳状态"""
        return cls._heartbeat(*args, **kwargs)
        

class ICMP(HeartBeat):

    @classmethod
    def _heartbeat(cls, host, port=None, timeout=4):
        resp = ping3.ping(host, timeout=timeout)
        if resp:
            return {'code': 0}
        if resp is None:
            return {'code': -1, 'detail': '超时'}
        return {'code': -1, 'detail': '异常'}


class TCP(HeartBeat):
    """端口探测"""

    @classmethod
    def _heartbeat(cls, host, port, timeout=10):
        try:
            with socket.create_connection((host, port), timeout) as sock:
                sock.shutdown(socket.SHUT_RDWR)
            return {'code': 0}
        except socket.timeout as e:
            return {'code': -1, 'detail': '超时'}
        except Exception as e:
            return {'code': -1, 'detail': '异常'}


class Http(HeartBeat):
    
    DefaultPort = {'http': 80, 'https': 443}

    def _build_url(self, scheme, host, port=None, path=''):
        url = f"{scheme}://{host}"
        if port is not None:
            url += f':{port}' if self.DefaultPort.get(scheme) != port else ''
        if path:
            url += f'/{path}' if not path.startswith('/') else path
        return url

    @classmethod
    def _heartbeat(cls, method, url, host=None, port=None, **kwargs):
        try:
            desire_code = kwargs.pop('desire_code')

            resp = requests.request(method, url, **kwargs)
            if not desire_code:  # 不校验状态码
                return {'code': 0}
            if resp.status_code != desire_code:
                return {'code': -1, 'detail': '状态码不匹配'}
            return {'code': 0}
        except requests.exceptions.Timeout as e:
            return {'code': -1, 'detail': '超时'}
        except requests.exceptions.SSLError as e:
            return {'code': -1, 'detail': '证书异常'}
        except Exception as e:
            return {'code': -1, 'detail': '错误'}


if __name__ == '__main__':
    print(ICMP.heartbeat('192.168.101.79'))
    print(TCP.heartbeat('192.168.101.79', 80))
    print(Http.heartbeat('get', 'https://192.168.101.79', desire_code=200))
